package fhv.at.imageprocessing.editors;

import java.awt.Choice;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyEditor;

import javax.media.jai.KernelJAI;

/**
 * Abstract class for all kernel editors
 * 
 * @author phru
 * 
 */
public abstract class KernelEditor extends Panel implements PropertyEditor {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private final TextField rows;
	private final TextField columns;
	private final TextArea matrix;
	private final Choice preDefinedKernels;

	protected PropertyChangeSupport pcs;
	protected KernelJAI kernel;
	private float[] kernelData;

	/**
	 * Create the panel.
	 */
	public KernelEditor() {
		setLayout(null);

		Label lblNewLabel = new Label("Zeilen");
		lblNewLabel.setBounds(10, 11, 46, 14);
		add(lblNewLabel);

		rows = new TextField();
		rows.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent e) {
				setMatrix();
			}
		});
		rows.setText("10");
		rows.setBounds(66, 8, 86, 20);
		add(rows);
		rows.setColumns(10);

		Label lblSpalten = new Label("Spalten");
		lblSpalten.setBounds(10, 36, 46, 14);
		add(lblSpalten);

		columns = new TextField();
		columns.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent e) {
				setMatrix();
			}
		});
		columns.setText("10");
		columns.setBounds(66, 33, 86, 20);
		add(columns);
		columns.setColumns(10);

		Label lblMatrix = new Label("Matrix");
		lblMatrix.setBounds(10, 61, 46, 14);
		add(lblMatrix);

		matrix = new TextArea();
		matrix.addKeyListener(new KeyAdapter() {
			@Override
			public void keyReleased(KeyEvent e) {
				valueChanged();
			}
		});
		matrix.setBounds(66, 64, 374, 225);
		add(matrix);

		preDefinedKernels = new Choice();
		preDefinedKernels.addItemListener(new ItemListener() {

			@Override
			public void itemStateChanged(ItemEvent e) {
				Choice cb = (Choice) e.getSource();
				String kernelName = cb.getSelectedItem();
				setPreDefinedKernel(kernelName);
			}
		});

		preDefinedKernels.setBounds(174, 8, 120, 20);
		preDefinedKernels.addItem("Default");
		preDefinedKernels.select(0);
		add(preDefinedKernels);

		pcs = new PropertyChangeSupport(this);

		setSize(450, 300);
	}

	public void addPreDefinedItem(String item) {
		preDefinedKernels.addItem(item);
	}

	public KernelJAI getKernel() {
		return kernel;
	}

	public void setKernel(Object kernel) {
		this.kernel = (KernelJAI) kernel;
	}

	private void setMatrix() {
		matrix.setText("");
		for (int i = 0; i < Integer.valueOf(rows.getText()); i++) {
			for (int j = 0; j < Integer.valueOf(columns.getText()); j++) {
				matrix.append("1.0  ");
			}
			matrix.append(System.getProperty("line.separator"));
		}
		valueChanged();
	}

	/* Kernel zusammensetzen */
	private void valueChanged() {
		try {
			kernelData = new float[Integer.valueOf(rows.getText())
					* Integer.valueOf(columns.getText())];

			String matrixString = matrix.getText()
					.replace(System.getProperty("line.separator"), " ")
					.replace("  ", " ");
			int valueCount = 0;
			String textAtIndex;
			String value = "";

			// fuer jedes Zeichen in der Matrix
			for (int i = 0; i < matrixString.length() - 1; i++) {
				// Zeichen an stelle i lesen
				textAtIndex = matrixString.substring(i, i + 1);
				// leerzeichen gefunden
				if (textAtIndex.equals(" ")) {
					// valeu gesetzt
					if (value.length() > 0) {
						// value als float in Array einfuegen
						kernelData[valueCount] = Float.valueOf(value);
						value = "";
						valueCount++;
					}
				} else {
					// value zusammenbauen
					value = value + textAtIndex;
				}
			}

			kernelData[valueCount] = Float.valueOf(value.replace("  ", " "));
			value = "";
			valueCount++;

			if (valueCount == Integer.valueOf(rows.getText())
					* Integer.valueOf(columns.getText())) {
				// alles ok
				kernel = new KernelJAI(Integer.valueOf(rows.getText()),
						Integer.valueOf(columns.getText()), kernelData);
				this.pcs.firePropertyChange("", null, null);
			}

		} catch (Exception e) {
			System.out.println(e);
		}
	}

	@Override
	public void addPropertyChangeListener(PropertyChangeListener pcl) {
		this.pcs.addPropertyChangeListener(pcl);
	}

	@Override
	public String getAsText() {
		return null;
	}

	@Override
	public Component getCustomEditor() {
		return this;
	}

	@Override
	public String getJavaInitializationString() {
		return null;
	}

	@Override
	public String[] getTags() {
		return null;
	}

	@Override
	public Object getValue() {
		return this.kernel;
	}

	@Override
	public boolean isPaintable() {
		return true;
	}

	@Override
	public void paintValue(Graphics g, Rectangle rec) {
		g.setColor(Color.BLACK);
		g.drawRect(0, 0, rec.width - 1, rec.height - 1);
	}

	@Override
	public void setAsText(String arg0) throws IllegalArgumentException {
	}

	@Override
	public void setValue(Object value) {
		matrix.setText("");

		this.kernel = (KernelJAI) value;

		this.rows.setText(String.valueOf(kernel.getHeight()));
		this.columns.setText(String.valueOf(kernel.getWidth()));

		int columnCount = 0;
		for (float f : kernel.getKernelData()) {
			this.matrix.append(String.valueOf(f));
			this.matrix.append("  ");
			columnCount++;
			if (columnCount >= kernel.getWidth()) {
				columnCount = 0;
				this.matrix.append(System.getProperty("line.separator"));
			}
		}
	}

	@Override
	public boolean supportsCustomEditor() {
		return true;
	}

	/* Vordefinierte Kernel erstellen */
	protected abstract void setPreDefinedKernel(String kernelName);

	protected void setKernelDefault() {
		float[] kernelData = { 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F, 1.0F,
				1.0F, 1.0F, };
		kernel = new KernelJAI(10, 10, kernelData);
		setValue(kernel);
	}
}
